/*******************************************************************************
 * Copyright (c) 2014 Steffen Mikkelsen
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the GNU Public License v3.0
 * which accompanies this distribution, and is available at
 * http://www.gnu.org/licenses/gpl.html
 * 
 * Contributors:
 *     Steffen Mikkelsen - initial API and implementation
 ******************************************************************************/
package com.subsecret.secureconnection.connectionpool;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.Socket;
import java.util.concurrent.ArrayBlockingQueue;

import com.subsecret.secureconnection.streamtools.StreamConstants;
import com.subsecret.secureconnection.streamtools.StreamTools;

public class ConnectionPoolClient implements Runnable {
    
    private final ArrayBlockingQueue<SocketHandler> pool;
    private final String host;
    private final int port;
    private final SocketCallback callback;
    
    public ConnectionPoolClient(String host, int port, int poolSize, SocketCallback callback) {
        pool = new ArrayBlockingQueue<>(poolSize);
        this.callback = callback;
        this.host = host;
        this.port = port;
    }
    
    public static ConnectionPoolClient createConnectionPool(String host, int port, int poolSize, SocketCallback callback) {
        return new ConnectionPoolClient(host, port, poolSize, callback);
    }
    
    @Override
    public void run() {
        while (true) {
            SocketHandler handler = new SocketHandler(host, port, callback);
            handler.start();
            pool.add(handler);
        }
    }
    
    public abstract static class SocketCallback {
        public abstract void callback(InputStream in, OutputStream out);
    }
    
    public static class SocketHandler extends Thread {
        private Socket socket;
        private InputStream in;
        private OutputStream out;
        private boolean makeReady = false;
        private SocketCallback callback;
        
        public static final int DELAY = 30;
        private long lastSubmit = System.currentTimeMillis();
        private String host;
        private int port;
        
        public SocketHandler(String host, int port, SocketCallback callback) {
            this.host = host;
            this.port = port;
            this.callback = callback;
        }
        
        public Socket makeReady() {
            makeReady = true;
            try {
                this.join();
                return socket;
            }
            catch (InterruptedException e) {
                e.printStackTrace();
            }
            return null;
        }
        
        @Override
        public void run() {
            try {
                socket = new Socket(host, port);
                in = socket.getInputStream();
                out = socket.getOutputStream();
                callback.callback(in, out);
            }
            catch (IOException e1) {
                e1.printStackTrace();
                return;
            }
            while (!makeReady) {
                try {
                    Thread.sleep(10);
                }
                catch (InterruptedException e) {
                    e.printStackTrace();
                }
                long passed = (System.currentTimeMillis() - lastSubmit) / 1000;
                if (passed > DELAY) {
                    lastSubmit = System.currentTimeMillis();
                    try {
                        StreamTools.sendByte(out, (byte) 0);
                        StreamTools.receiveByte(in);
                    }
                    catch (IOException e) {
                        e.printStackTrace();
                        break;
                    }
                }
            }
            try {
                StreamTools.sendByte(out, StreamConstants.STREAM_READY);
            }
            catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}
